package com.sdy.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.sdy.po.Parm;
import com.sdy.po.RealTimeDataQueue;
import com.sdy.service.ClusterService;
import com.sdy.service.CompanyServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/serialData/{name}")
@SuppressWarnings("all")
public class WS_RealTimeData {


    /**
     * webSocket是多对象，与spring中@Autowired冲突
     * 所以必须这样注入
     */
    private static CompanyServiceImpl companyService;
    @Autowired
    public void setCompanyService(CompanyServiceImpl companyService) {
        WS_RealTimeData.companyService = companyService;
    }

    //实时数据的队列Map
    Map<String,RealTimeDataQueue> queueMap = new HashMap<>();

    private static ClusterService clusterService;
    @Autowired
    public void setCompanyService(ClusterService clusterService) {
        WS_RealTimeData.clusterService = clusterService;
    }

    /**
     *  与某个客户端的连接对话，需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户名
     */
    private String name;

    /**
     * 转发到网页数据的中间对象
     */
    private JSONObject jsonToWeb;

    /**
     * 转发到集群的中间对象
     */
    private JSONObject jsonToCluster;

    /**
     *  用于存所有的连接服务的客户端，这个对象存储是安全的
     */
    private static ConcurrentHashMap<String, WS_RealTimeData> webSocketSet = new ConcurrentHashMap<>();


    @OnOpen
    public void OnOpen(Session session, @PathParam(value = "name") String name){
        this.session = session;
        this.name = name;
        // name是用来表示唯一客户端，如果需要指定发送，需要指定发送通过name来区分
        webSocketSet.put(name,this);
        System.out.println(name);
        //判段是否来自web的socket连接
//        if(!name.substring(0,3).equals("web")){
//            //如果不是，回传串口数据
////            SerialInfoSending(name);
//        }
        System.out.println("[WebSocket] 连接成功，当前连接人数为：=" + webSocketSet.size());
    }


    @OnClose
    public void OnClose(){
        webSocketSet.remove(this.name);
        System.out.println("[WebSocket] 退出成功，当前连接人数为：=" + webSocketSet.size());
    }

    @OnMessage
    public void OnMessage(String message){
        System.out.println("[WebSocket] 收到消息：" + name + message);
        JSONObject msg = JSON.parseObject(message);
        Parm parm = JSON.parseObject(msg.get("parm").toString(),new TypeReference<Parm>(){});
        Boolean isHandled = (Boolean) msg.get("isHandled");
        String parmName = parm.geteName();

        //将到达的数据加入队列
        insertDataToQueue(parmName,isHandled,parm,msg);
        //获得队列的信息
        JSONObject jsonObject = getSequenceQueue(parmName,isHandled,parm);
        //将队列信息放入redis中,只管处理后的
        if (isHandled){
            companyService.setParmState((Integer) msg.get("companyId"),parm,jsonObject);
        }
        //重置redis中识别码冷却时间
        companyService.updateExpirationTime(name, (Integer) msg.get("companyId"),10);
        //发送数据
        sendMessageToClient(jsonObject);
        //将数据放入集群中
        clusterService.insertData(JSON.parseObject(message));
        //向集群添加模拟数据
//        setVirtualDataToCluster(JSON.parseObject(message));
    }

    /**
     * 将其传回相关网页
     * @param parmName
     * @param isHandled
     * @param parm
     */
    private void sendMessageToClient(JSONObject jsonObject){
        List<WS_RealTimeData> wsList = findClientByBasicKey(name);
        if(wsList.size()>0){
            String message = jsonObject.toJSONString();
            for (WS_RealTimeData WSRealTimeData :wsList) {
                //将排列好的数据队列转发给网页
                AppointSending(WSRealTimeData.getName(),message);
            }
        }
    }

    /**
     * 模糊查找连接池中的连接
     */
    public List<WS_RealTimeData> findClientByBasicKey(String basickey){
        List<WS_RealTimeData> WSRealTimeDataList = new ArrayList<>();
        for (Map.Entry entry:webSocketSet.entrySet()) {
            //连接池中有其他频道在监听{name}串口，且不是{name}本身
            if (entry.getKey().toString().indexOf(basickey) > 0){
                WSRealTimeDataList.add((WS_RealTimeData) entry.getValue());
                System.out.println(WSRealTimeDataList);
            }
        }
        if (WSRealTimeDataList.size() == 0){
            System.out.println("无人监听，redis状态要改变");
        }
//        System.out.println(webSocketList.size());
        return WSRealTimeDataList;
    }

    /**
     * 群发
     * @param message
     */
    public void GroupSending(String message){
        for (String name : webSocketSet.keySet()){
            try {
                webSocketSet.get(name).session.getBasicRemote().sendText(message);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 将传回的数据插入队列中
     * @param parmName
     * @param isHandled
     * @param parm
     * @param jsonObject
     * @return
     */
    private RealTimeDataQueue insertDataToQueue(String parmName,Boolean isHandled,Parm parm,JSONObject jsonObject){
        String queueName = parmName + "-" + isHandled;
        RealTimeDataQueue queue = queueMap.get(queueName);
        if (queue == null){
            System.out.println("需要创建一个队列");
            queue = new RealTimeDataQueue(25,parm);
            queueMap.put(queueName,queue);
        }
        queue.insertDataToQueue(jsonObject);
        return queue;

    }

    /**
     * 获得相应的，排列好的队列
     * @param jsonObject
     * @return
     */
    private JSONObject getSequenceQueue(String parmName, Boolean isHandled,Parm parm){
        RealTimeDataQueue queue = queueMap.get(parmName + "-" + isHandled);
        JSONObject result = queue.getSequenceQueueAndState();
        result.put("parmName",parmName);
        result.put("isHandled",isHandled);
        return result;
    }

    /**
     * 收到的串口数据转发回对应客户端
     * @param name
     * @param message
     */
    public void AppointSending(String name,String message){
//        stringToJson(message);
        try {
            webSocketSet.get(name).session.getBasicRemote().sendText(message);
            //复制出其他检测项的模拟数据
            getVirtualData(name,message);
            System.out.println("实时数据回传完毕");
        }catch (NullPointerException nullPointerException){
            System.out.println(name + "网页没有建立连接，redis状态要改变");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //向集群添加模拟数据
    public void setVirtualDataToCluster(JSONObject jsonObject){
        Parm parm = JSON.parseObject(jsonObject.get("parm").toString(),new TypeReference<Parm>(){});

        parm.seteName("sulfurDioxide");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);

        parm.seteName("nitrogenOxide");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);

        parm.seteName("particulate");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);

        parm.seteName("flow");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);

        parm.seteName("humidity");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);

        parm.seteName("oxygenContent");
        jsonObject.put("parm",JSON.toJSONString(parm));
        clusterService.insertData(jsonObject);
    }

    //测试需要，模拟其他串口的数据
    public void getVirtualData(String name, String message)  {
        JSONObject jsonObject = JSON.parseObject(message);
        try {
            jsonObject.put("parmName","sulfurDioxide");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
            jsonObject.put("parmName","nitrogenOxide");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
            jsonObject.put("parmName","particulate");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
            jsonObject.put("parmName","flow");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
            jsonObject.put("parmName","humidity");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
            jsonObject.put("parmName","oxygenContent");
            webSocketSet.get(name).session.getBasicRemote().sendText(jsonObject.toJSONString());
        } catch (IOException e) {
            System.out.println("没建立网络连接");
        }
    }

    /**
     * 获取连接的name
     * @return
     */
    public String getName() {
        return name;
    }
}
